{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "raw_mimetype": "text/restructuredtext"
   },
   "source": [
    ".. _nb_mixed_variable:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Mixed Variable Problem\n",
    "\n",
    "In some cases variable might have different types, some might be real and others integer valued. For those cases, different evolutionary operators must be applied to different type of variables. In *pymoo* this is supported by instantiating operators with a mask. Let us consider the following optimization problem with two variables:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "from pymoo.model.problem import Problem\n",
    "\n",
    "class MyProblem(Problem):\n",
    "\n",
    "    def __init__(self):\n",
    "        super().__init__(n_var=2, n_obj=1, n_constr=1, xl=0, xu=10)\n",
    "\n",
    "    def _evaluate(self, x, out, *args, **kwargs):\n",
    "        out[\"F\"] = - np.min(x * [3, 1], axis=1)\n",
    "        out[\"G\"] = x[:, 0] + x[:, 1] - 10"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Where we would like to keep the first variable in integer and the second variable a real value. Therefore, we first define a mask that defines the type for each variable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "# if the first variable is an integer and the second a real value\n",
    "mask = [\"int\", \"real\"]\n",
    "\n",
    "# e.g. if first two are integers and third real it would be\n",
    "# mask = [\"int\", \"int\", real\"]\n",
    "# for the purpose of plotting we limit us to two variables here"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Furthermore, all operators which are necessary to run the algorithm must be defined. The mixed variable classes allow to reuse existing operator and apply in inside the mask during running time. The keys of the dictionary must match with the keywords used in the mask. Internally, the mating considers each type of the mask separately, applies the operator and finally concatenates the results. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "from pymoo.factory import get_sampling, get_crossover, get_mutation\n",
    "from pymoo.operators.mixed_variable_operator import MixedVariableSampling, MixedVariableMutation, MixedVariableCrossover\n",
    "\n",
    "sampling = MixedVariableSampling(mask, {\n",
    "    \"real\": get_sampling(\"real_random\"),\n",
    "    \"int\": get_sampling(\"int_random\")\n",
    "})\n",
    "\n",
    "crossover = MixedVariableCrossover(mask, {\n",
    "    \"real\": get_crossover(\"real_sbx\", prob=1.0, eta=3.0),\n",
    "    \"int\": get_crossover(\"int_sbx\", prob=1.0, eta=3.0)\n",
    "})\n",
    "\n",
    "mutation = MixedVariableMutation(mask, {\n",
    "    \"real\": get_mutation(\"real_pm\", eta=3.0),\n",
    "    \"int\": get_mutation(\"int_pm\", eta=3.0)\n",
    "})"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Finally, as usual the optimization method is called with the operators defined above:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Best solution found: [3 6.994769535604938]\n",
      "Function value: [-6.994769535604938]\n",
      "Constraint violation: [-0.0]\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "from pymoo.algorithms.so_genetic_algorithm import GA\n",
    "from pymoo.factory import get_crossover, get_mutation, get_sampling\n",
    "from pymoo.optimize import minimize\n",
    "\n",
    "problem = MyProblem()\n",
    "\n",
    "algorithm = GA(\n",
    "    pop_size=20,\n",
    "    sampling=sampling,\n",
    "    crossover=crossover,\n",
    "    mutation=mutation,\n",
    "    eliminate_duplicates=True,\n",
    ")\n",
    "\n",
    "res = minimize(\n",
    "    problem,\n",
    "    algorithm,\n",
    "    ('n_gen', 200),\n",
    "    seed=1,\n",
    "    save_history=True\n",
    ")\n",
    "\n",
    "print(\"Best solution found: %s\" % res.X)\n",
    "print(\"Function value: %s\" % res.F)\n",
    "print(\"Constraint violation: %s\" % res.CV)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuIAAAHwCAYAAADjFQoyAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAWJQAAFiUBSVIk8AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjEsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8QZhcZAAAgAElEQVR4nOzde3RU9bn/8c83RAhCBEO49AiEhECJKMWEixhqgmk5eKEeQYFe6AFt67lwQNuC0F9t8dJCoVWhaMvqQTlSl4oCx0IVrREiROSWChbhQEwIoBIIAR3ABMPs3x9DEMhtZmf23jOT92utrMjs/UyejCF8svPs79dYliUAAAAA7orzugEAAACgJSKIAwAAAB4giAMAAAAeIIgDAAAAHiCIAwAAAB4giAMAAAAeIIgDAAAAHiCIAwAAAB4giAMAAAAeIIgDAAAAHiCIAwAAAB4giAMAAAAeiPe6AScYY0olXSFpv8etAAAAILb1kvSZZVmpoRbGZBCXdEXbtm2TMjIykrxuBAAAALFr9+7d+vzzz23VxmoQ35+RkZG0fft2r/sAAABADMvKylJRUdF+O7XMiAMAAAAeIIgDAAAAHiCIAwAAAB4giAMAAAAeCEsQN8bcaYz5vTFmgzHmM2OMZYz5cxM1NxhjXjXGVBpjPjfG7DTG3GeMaRWOngAAAIBIFq5VU34u6WuSTko6JKlfYycbY26XtEJSlaQXJVVKGi3pcUnZku4KU18AAABARArXaMr9kvoqsInOvzd2ojHmCkl/knRWUq5lWfdYljVd0kBJmyTdaYyZEKa+AAAAgIgUliBuWdY6y7L2WZZlBXH6nZI6S3rBsqxtFzxHlQJX1qUmwjwAAAAQ7by4WfOmc+/X1nPsbUmnJd1gjGnjXksAAACAu7zYWfOr597vvfSAZVk1xphSSf0lpUna3dgTGWMa2jqz0Rl1AAAAwGteXBHvcO79pw0cr328owu9AAAAAJ7w4op42FiWlVXf4+eulGe63A4AAAAQNC+uiNde8e7QwPHax0+40AsAAADgCS+C+P+de9/30gPGmHhJqZJqJJW42RQAAADgJi+C+Fvn3o+q59iNki6X9I5lWdXutQQAAAC4y4sg/rKkCkkTjDGDah80xiRIevTcH//gQV8AAACAa8Jys6Yx5l8k/cu5P3Y7936YMWbpuf+usCzrp5JkWdZnxpgfKhDI1xtjXlBgi/tvKbC04csKbHsPAABasiO7pZICqdontUmU0nKkLhledwWETbhWTRko6V8veSzt3JsklUn6ae0By7L+1xiTI+n/SRorKUFSsaQfS1oY5A6dAAAgFpWslwrmSWWFdY+lZEs5M6S0XJebAsIvLEHcsqzZkmaHWFMo6ZZwfHwAABAjip6VVk+TLH/9x8sKpWV3SKMXSpkT3e0NCDMvZsQBAADqKlnfeAivZfml1VMD5wNRLKo39AGiAjOOABCcgnlNh/Ball8qmM+ICqIaQRxwCjOOABC8I7vr/37ZmLKNgToubiBKMZoCOKHo2cAMY0P/qNTOOBYtc7cvAIhUJQXu1gERgCAOhBszjgAQumqfu3VABCCIA+FmZ8YRAFq6Nonu1gERgCAOhFNzZhwBoCVLy3G3DogABHEgnJhxBAB7umQEbmQPRcpwbtREVCOIA+HEjCMA2JczQzJBRhMTJ+VMd7YfwGEEcSCcmHEEAPvScqXRC5oO4yYusLNmWq7zPQEOIogD4cSMIwA0T+b3pYmrAmMn9UkZHjjO9vaIAWzoA4RT7YxjKDdsMuMIABdLyw28sTMxYhxBHAi3nBmBzXqCWcKQGUcAaFiXDII3YhqjKUC4peUy4wgAAJpEEAecwIwjAABoAqMpgFPScplxBAAADSKIA05jxhEAANSD0RQAAADAAwRxAAAAwAMEcQAAAMADBHEAAADAAwRxAAAAwAMEcQAAAMADBHEAAADAAwRxAAAAwAMEcQAAAMADBHEAAADAA2xxD0csLSzVC1sP6vSZGl3eOl4TBvfQpOxUr9sCAACIGARxhNWsFTu1fNtBnbUufnz26g/0yJoPNG5QD80ZO8Cb5gAAACIIQRxhM+apQhUdONHg8bOW9PzWg9p35KRe/vcbXOwMAAAg8jAjjrCYtWJnoyH8QtvKjmvWip0OdwQAABDZCOIIi+XbDjp6PgAAQKwhiKPZlhaW1pkJb8pZK1AHAADQUjEjjmZ7Yau9q9svbD3ISioAAo7slkoKpGqf1CZRSsuRumR43RUAOIogjmY7fabG1ToAMaRkvVQwTyorrHssJVvKmSGl5brcFAC4g9EUNNvlre39PGe3DkCMKHpWWnZH/SFcCjy+7A6paJm7fQGASwjiaLYJg3u4WgcgBpSsl1ZPkyx/4+dZfmn11MD5ABBjCOJotknZqTIh1phzdQBaqIJ5TYfwWpZfKpjvbD8A4AGCOMIixEVTQj4fQAw5srvhcZSGlG0M1AFADCGIo9nsLkPI8oVAC1VS4G4dAEQogjiarTnLFwJogap97tYBQIQiiKPZWL4QQEjaJLpbBwARiiCOZmP5QgAhSctxtw4AIhRBHM3G8oUAQtIlI7BZTyhShrPTJoCYQxBHs03KTlWrENcvbGVYvhBo0XJmSCbIf4JMnJQz3dl+AMADBHGExbhBoV3dDvV8ADEmLVcavaDpMG7ipNEL2eYeQEwiiCMs5owdoMyeHYM6d1DKlZozdoDDHQGIeJnflyauCoyd1CdleOB45kR3+wIAl3C3HMJm5X9ka9aKnVq+7aDO1rNjTysTuBJOCAdwXlpu4O3I7sA64dW+wOooaTnMhAOIeQRxhNWcsQM0Z+wALS0s1QtbD+r0mRpd3jpeEwb3YCYcQMO6ZBC8AbQ4BHE4YlJ2KsEbAACgEcyIAwAAAB7gijgAAJGEeXmgxSCIAwAQCUrWSwXzpLLCusdSsgNrr6flutwUACcxmgIAgNeKnpWW3VF/CJcCjy+7Qypa5m5fABxFEAcAwEsl66XV0yTL3/h5ll9aPTVwPoCYQBAHAMBLBfOaDuG1LL9UMN/ZfgC4hiAOAIBXjuxueBylIWUbA3UAoh5BHAAAr5QUuFsHIKIQxAEA8Eq1z906ABGFIA4AgFfaJLpbByCiEMQBAPBKWo67dQAiCkEcAACvdMkIbNYTipTh7LQJxAiCOAAAXsqZIZkg/zk2cVLOdGf7AeAagjgAAF5Ky5VGL2g6jJs4afRCtrkHYki81w0AQIt1ZHdgGbpqX+Dmu7QcRg5aqszvSx17BjbrKdtY93jK8MCV8LRctzsD4CCCOAC4rWR9YDfF+jZySckOjCqk5brcFDyXlht44wc0oMXwNIgbY26VNE3S1ZI6SfpE0nZJj1mWtcnL3gDAEUXPSqunNbyleVmhtOyOwAhC5kR3e0Nk6JJB8AZaCM9mxI0xv5G0RlKmpLWSFkgqknS7pEJjzPe86g0AHFGyvvEQXsvyS6unBs4HAMQsT66IG2O6SfqppHJJAyzLOnLBsRGS3pL0sKQ/e9EfADiiYF7TIbyW5Q/MC6flOtkRAMBDXl0RTzn3sTdfGMIlybKsdZJ8kjp70RgAOOLI7vpnwhtTtjFQBwCISV4F8X2SzkgaYoxJvvCAMeZGSYmS3vSiMQBwREmBu3UAgIjnyWiKZVmVxpgHJD0m6QNjzP9KOiapt6RvSfqbpHubeh5jzPYGDvULV69Ac416okB7Dp88/+d+3dpr7X1sT93iVPvcrQMARDzPVk2xLOsJY8x+SU9L+uEFh4olLb10ZAWINtf+cq181WfrPL7n8En1mvlXJbZppfcfGuVBZ/BEm0R36wAAEc/LVVNmSHpZ0lIFroS3k5QlqUTSc8aYeU09h2VZWfW9SdrjYOtAk1Jn/rXeEH4hX/VZpc78q0sdwXNpNn8LYrcOABDxPAnixphcSb+R9BfLsn5sWVaJZVmnLcsqknSHpI8k/cQYk+ZFf0BzXPvLtbKCPNc6dz5agC4Zgc16QpEynPWkASCGeXVF/LZz79ddesCyrNOStijQ23VuNgWEQ1NXwpt7PqJYzgzJBPlt18QFtjQHAMQsr4J4m3PvG1qisPbxMy70AoTNqCfsrXBhtw5RJi1XGr2g6TBu4gI7a6blOt8TAMAzXgXxDefe/8gYc9WFB4wxN0vKllQl6R23GwOa48LVUdyoQxTK/L40cVVg7KQ+KcMDx9neHgBinlerpryswDrh35C02xizStJhSRkKjK0YSTMtyzrmUX8A4Jy03MDbkd2BdcKrfYHVUdJymAkHgBbEq3XE/caYWyT9p6QJCtygebmkSkmvSlpoWdYbXvQGAK7pkkHwBoAWzMt1xL+Q9MS5NyAm9OvW3taYSb9u7R3oBgAARDLP1hEHYpHdHTPZaRMAgJaHIA6E0d5ye9uR260DAADRiyAOhFFhcYWrdQAAIHoRxIEwOllV42odAACIXgRxIIxWFh10tQ4AAEQvgjgQRmWVn7taBwAAohdBHAgjy+U6AAAQvQjiQBjZ/QvFX0QAAFoe/v0HwmhY706u1gEAgOhFEAfC6O9lx12tAwAA0cuzLe4R2/aW+1RYXKGTVTVqnxCv7PRk9e2a6HVbjjv1hd/VOgAAEL0I4girwuIKLcjfpy2llXWODUlN0rS8PspOT/agMwAAgMjCaArC5sWtBzRxyeZ6Q7gkbSmt1MQlm7V8K2tmAwAAEMQRFoXFFZq18n35m1iHz29JM1fuZEt3AADQ4hHEERYL8vc1GcJr+S1pYf4+ZxsCAACIcARxNNvecl+D4ygN2Vxaqb3lPoc6AgAAiHwEcTSb3TGTWBxPMS7XAQCA6EUQR7OdrKpxtS6StW/TytU6AAAQvQjiaLb2CfZWwbRbF8mCHJMPWx0AAIheBHE0m911wVlPHAAAtGQEcTTbOzZnve3WRbLLW9u7ym+3DgAARC+COJrtBZsb9Niti2R3Zl3lah0AAIheBHE02+kz9m66tFsXyWaMynC1DgAARC+COJqNcQwAAIDQkYTQbBMG99Ds1R/Yqos1o54osF239r6cMHcTedJ+8bRatSuWiauS5U/Q2VPpKnn4bq/bAgDAEwRxNNuk7FQ9suYDnQ1hDb5WJlAXa/YcPulqXbTo/fACtU7OV7vepXWOZTz1vzpTkacPfzHNg84AAPAOoykIixv7dnb0fESvPnNmq23PJYpvVyrrkh/WLEuKb1eqtj2XKH3ObE/6AwDAK1wRD6M3dh3WyqJD8lXVKDEhXmMyu2tk/25et+WKTz6tCun8wyGej+jU++EFattzpYwJJHBjLj5e+2djLCV8ZaV6P3wlV8YBAC0GQTwMFhd8qEXriuW7ZMv2tbvKlZgQrykj0nVvTm+PunPe3nKf9hz2hVSz+7BPe8t96ts10aGuvNGvW3tbYyb9urV3oBvvtU7OPx/Cm2KMpdbJ+ZII4gCAloHRlGb6yfL3NOe1PXVCeC1fVY3mvLZH01/a4XJn7ln1949crYtkdm+4jMUbNdN+8XS94ygNqR1TSfvF0842BgBAhOCKeDMsLvhQK4qCC5MvbT+k9C7tY/LK+J5PPnO1LpItLax7M2KwdbF282qrdsWS6o6jNKT2vNq6FuHIbqmkQKr2SW0SpbQcqQtrygNAS0EQb4ZF60ILDIvWFcdkEMeXmrPLaKwFcRNn7z4Au3VRpWS9VDBPKiuseywlW8qZIaXlutwUAMBtjKbY9Mauww2OozTEV1WjN3Yddqgj7/T7ir05b7t1kYxdRr9k+RNcrYsaRc9Ky+6oP4RLgceX3SEVLXO3LwCA6wjiNq0sOuRqXSS747rurtZFMnYZ/dLZU+mSFNKM+IV1MalkvbR6mmT5Gz/P8kurpwbOBwDELIK4TaFeDW9uXSTr2zVRX+0W2tXtft0SY27FFMn+bqGxuMuo/0xX1ZxKDWlGvOZUqvxnujrbmJcK5jUdwmtZfqlgvrP9AAA8RRC3KTHB3hVMu3WR7he3Xa0g85aMpAdvu9rJdjxjd8471ubDa52pyJNlBfeVYVlGZyryHO7IQ0d2NzyO0pCyjYE6AEBMIojbNCbT3liF3bpIl52erLljr20yjBtJvxk7QNnpyW60BY+dPZ2u6k/GnA/j9e2sGXhvVPXJGJ09HctjKQXu1gEAIh5B3KaR/buFfHU7MSE+pnfaHD+4p/78g6EamppU7/GhqUn68w+GalwMjmHU+t5/v+tqXTT44tPB+vzAPfWOqdSOo3x+4B7VfDrYmwbdUh3aplfNrgMARLzYnJNwyZQR6Zrz2p6Qzo912enJyk5P1t5ynwqLK3SyqkbtE+KVnZ4ckzPhl9r04TFX66LF2dPp+vxAuuJal6tVu2KZuCpZ/gSdPZUe2zPhF2pj8+vfbh0AIOIRxJvh3pze2lvuC2pTn7uyureoNcT7do3NmzGbEuRteGGrizb+M11bTvC+VJrN3VPt1gEAIh6jKc30u3EDNevmfg2OqSQmxGvWzf00/66vudwZvGD3LxR/EVuALhmBzXpCkTKcnTYBIIZxRTwM7s3prXtzeuuNXYe1suiQfFU1SkyI15jM7jE9E466hvXupI3FoY+ZDOvdyYFuEHFyZgQ26wlmCUMTJ+VMd74nAIBnCOJhNLJ/N4J3C/fnH1yvXjP/aqsOLUBarjR6QdOb+pg4afRCtrkHgBjHb8SBMNpbbm+FC7t1iEKZ35cmrgqMndQnZXjgeOZEd/sCALiOK+JAGBUWV9iua4k3t7ZYabmBtyO7A+uEV/sCq6Ok5TATDgAtCEEcCKOTVTWu1iHKdckgeANAC8ZoChBG7UPc5Km5dQAAIHoRxIEwyk5PdrUOAABEL4I4EEZ9uyZqSGpSSDVDU5OYDwcAoAUiiANhNi2vj+JMcOfGGWlqXh9nGwIAABGJIA6EWXZ6suaMubbJMB5npLljBjCWAgBAC8UdYoADxg/uqe5XXq6F+fu0ubSyzvGhqUmamteHEA4AQAtGEAcckp2erOz0ZO0t96mwuEInq2rUPiFe2enJzIQDAACCOOC0vl0TCd4AAKAOZsQBAAAAD3BFHHDYG7sOa2XRIfmqapSYEK8xmd01sn83r9sCAAAeI4gDDllc8KEWrSuW75Lt69fuKldiQrymjEjXvTm9PeoOAAB4jSAOOOAny9/TiqKPGjzuq6rRnNf2qPjISc2/62sudgYAACIFM+JAmC0u+LDREH6hl7Yf0uKCDx3uCAAARCKCOBBmi9YVO3p+tNg/91ZX6wAAiDYEcSCM3th1uM5MeFN8VTV6Y9dhhzryzqgnClytAwAg2hDEgTBaWXTI1bpItufwSVfrAACINgRxIIxCvRre3DoAABC9COJAGCUm2FuIyG4dAACIXgRxIIzGZHZ3tQ4AAEQvLsPBEXvLfSosrtDJqhq1T4hXdnqy+nZN9Lotx43s301GkhVCjTlXBwAAWhbPg7gxJk/SFEnDJF0p6Zik9yUtsCzrVS97Q+gKiyu0IH+ftpRW1jk2JDVJ0/L6KDs92YPO3BNKCLdzPgAAiA2eBnFjzDxJ0yUdkvQXSRWSOkvKkpQriSAeRV7cekCzVr4vfwPJcktppSYu2ay5YwZo3OAe7jbnkpkrdtiumzuWHTZbmpkrdmjNzk/0xVlLl7Uyum3AV/g6AIAWxLMgboz5oQIh/H8k/ciyrDOXHL/Mk8ZgS2FxRaMhvJbfkmau3Kmrrmwbk1fG/7LjY9t1BLCW4/ZFG7Xj0KcXPVZdI72w9ZBe2HpIX+veQa9MGe5RdwAAt3hys6Yxpo2kX0k6oHpCuCRZlvWF643BtgX5+5oM4bX8lrQwf5+zDXnkTI29QRO7dYg+mY+8USeEX2rHoU+V9cjfXOoIAOAVr66If1OBEZQnJPmNMbdKukZSlaQtlmVtCuZJjDHbGzjULyxdIih7y331zoQ3ZnNppfaW+2LuBs44424dosvtizaq8lRw1xiOnTqj2xdt5Mo4AMQwr4L44HPvqyT9XYEQfp4x5m1Jd1qWddTtxhC6wuIK23WxFsT7/9MV+vvBxq92NlQXa65o00qfVZ+1VRermroS3tzzAQDRxat1xLucez9dgUUjvi4pUdIASW9IulHSS009iWVZWfW9SdrjUN+ox0mbu0LarYtkv7nT3py33bpI5rMRwptTF+macyMvACA2eRXEaz9ujaRvWZa10bKsk5ZlvS/pDgVWUckxxgzzqD+EoL3NXSHt1kWyvl0TFeqUiTlXF2vsTr3H6rT8mp2fuFoHAIh8XgXxE+fe/92yrP0XHrAs67Sk18/9cYibTcEeu6ufxOKqKRLriNeyO/Yeq+PyX5y193/abh0AIPJ5FcT/79z7Ew0cP37ufVsXekEz7a845WpdJGP84EsDe3RwtS7SXdbK3o8YdusAAJHPqyCer8CFwKuNMfX1UHvzZql7LcGulUWHXK2LZIwffGnVf9pb7cNuXaS7bcBXXK0DAEQ+T4K4ZVllklZL6ilp2oXHjDEjJf2zAlfL17rfHULls3nTpd26SMb4wcXiQ/wOE+r50cTuhk1s9AQAscvLf/b+U9JBSY8ZY940xsw3xryswLb2ZyX9wLIs1u6KAok2b7q0WxfJGD/40t5yn2r8odXU+AN1sepr3UMbuwn1fABAdPEsiFuWdUhSlqRFkvoocGU8V4Er5dmWZa3wqjeEZkxmd1frIhnjB19qzvryseqVKcOV1O6yoM7t1K41m/kAQIzz9BfBlmUdtSzrvyzLSrEsq7VlWcmWZd1hWdYWL/tCaHolt3O1LpIxfvAl1pevX9GDI5u80v217h20/cFvutQRAMArMTyRCbdw5fNijB8EsL58w2aM6qchqUn1HhuSmqQZo/q53BEAwAsEcTQbVz4v9sqU4Qp25LuVUcyOH7C+fP1e3HpAE5ds1pbSynqPbymt1MQlm7V860GXOwMAuI0gjmY7/YW9Lcnt1kW6WSt2KthFUM5agfNjUd+uiQ1e9W3I0NSkmNxltFZhcYVmrXxf/ia+PvyWNHPlzpj9rREAIIAgjjBgM/MLLd8W2pXMUM+PJtPy+iguyN8OxBlpal4fZxvy2IL8fU2G8Fp+S1qYv8/ZhgAAniKIo9kuv8zeTK/duki2tLA06Kvhtc5agbpYlJ2erDljrm0yjMcZae6YATE9lrK33NfgOEpDNpdWxvRyjgDQ0hHE0WzclPelF2zO9dqtiwbjB/fUsnuGamgDYypDU5O07J6hGje4h8uduYubmgEAl4q9JATXcVPel06fsXcDqt26aJGdnqzs9GTtLfepsLhCJ6tq1D4hXtnpyTE9E34hbmoGAFyKII5mq70pL5Rfu8fqTXmXt7Y5pmOzLtr07ZoYk//fg8FvjgAAl2I0BWHBTXkBE2yOV9itQ/TgN0cAgEsRxBEW3JQXMCk7Neg1xGu1MoG6luDf/7xNff/fq+r9s1fV9/+9qn//8zavW3INyzkCAC7F7zwRNuMH91T3Ky/Xwvx92lzPmMrQ1CRNzesTsyG81rhBPfR8CDdfjhsU+1fDb/rtepVUnLrosbOSXvtHuXrN/KvSktvprZ/metKbm6bl9dHEJZuDWsIwln9zBADNcmS3VFIgVfukNolSWo7UJcPrrmwhiCOsuClPmjN2QEhBfM7YAQ52473+v1irU2ca37yppOKU+v9irXY9PMqlrryRnZ6s+DijM0GscRkfZ2L+h1YACEnJeqlgnlRWWPdYSraUM0NKy3W5qeZhNAWO6Ns1UZOzU/VfeX00OTu1xYRwSRr263xHz48mN/12fZMhvNapM2d102/XO9uQx2767fqgQrgknTlrxfzrAQBBK3pWWnZH/SFcCjy+7A6paJm7fTUTQRwIs08+q3L0/Ghy6ThKuM+PNrweAGBDyXpp9TTJ8jd+nuWXVk8NnB8lCOJAGH3vv991tS6S2b0RM1Zv4OT1AACbCuY1HcJrWX6pYL6z/YQRQRwIo00fHnO1LpLl7z7ial2k4/UAABuO7G54HKUhZRsDdVGAIA6EUZA/r4etLpIFOQodtrpIx+sBADaUFLhb5zKCOBBGdv9CxeJfRH8wa/SFsS7Shbq+fHPrACAmVPvcrXNZLP77D3hmWO9OrtZFsstsJki7dZEuL6OLq3UAEBPa2Fx1zW6dywjiQBj9+QfXu1oXydq2buVqXaT7w/cGuVoHADEhLcfdOpcRxIEw+8oVCY6eHy3axNsL1HbrokFacjtHzweAmNMlI7BZTyhShkfNTpsEcSDMNv0sT62DHK9o3cpo08/yHO7IG3dmXeVqXTR466e5ahfkFf92rVvprZ/mOtsQAESDnBmSCTKymjgpZ7qz/YQRQRxwwN5f3dJkGG/dymjvr25xqSP3zRhl72qE3bposevhUU1e6U5LbqddD49yqSMAiHBpudLoBU2HcRMnjV4YVdvcE8QBB9w4760mtzI/c9ZS7vx1LnWESPLWT3O1f+6tuvmarmrdyqhVnFHrVkY3X9NV++feypVwALhU5veliasCYyf1SRkeOJ450d2+mine6waAWDP5mS06UPl5UOfuP3Zak5/ZomcmD3G4K/c1ZyfJlnKDYkv5PAEgLNJyA29HdgfWCa/2BVZHScuJmpnwSxHEgTBb939HHT0/WrCTJADAEV0yojZ4X4rRFCCM5q21t6Wu3bpIxk6SAAA0jiAOhNHL2z9ytS6SsZMkAACNI4gDYVRdc9bVukjGTpIAADSOIA6EEZvYfImdJAEAaBxBHAgjNrG5GDtJAgDQMII4EEZsYnMxdpIEAKBhBHEgjFg1pa6vdksM6ryMr1zhcCcAAEQWgjgQRqyacrFZK3aq6MCJoM7dVnZcs1bsdLgjAAAiB0EcCCNWTbnY8m0HHT0fAIBoRhAHwohVU760tLA05M15zlqBOgAAWgKCOBBGrJrypRe22ru6bbcOAIBoQxAHwohVU7706ekzrtYBABBtCOJAmI34amdHz48WoY6lNLcOAIBoQxAHwuyZyUPUM6ltUOf26nS5npk8xOGOvHFFQryrdQAARBuCOOCAt2fc1OSV7hFf7az100e41JH7Pjrxuat1AABEGy49AQ6pvdI9b+1uvbz9I1XXnFWb+Fa6M+uqmJwJv1R1jd/VOgAAog1BHHDYjFEZLSJ4AwCA0DCaAh6ydy8AACAASURBVMARl7e2tza63ToAAKINV8QBOOL7w1L01PoSW3Utxd5ynwqLK3SyqkbtE+KVnZ6svl0TvW4LAOASgjgAR8wYlWEriLeEMZ7C4gotyN+nLaWVdY4NSU3StLw+yk5P9qAzAICbGE0B4BjWVK/rxa0HNHHJ5npDuCRtKa3UxCWbtZwdRgEg5hHEATjm+rROjp4fbQqLKzRr5fvyN7Fpkd+SZq7cqcLiCncaAwB4giAOwDGL1hU7en60WZC/r8kQXstvSQvz9znbEADAUwRxAI54Y9dh+apqQqrxVdXojV2HHerIW3vLfQ2OozRkc2ml9pb7HOoIAOA1gjgAR6wsOuRqXaSzO2bCeAoAxC6COABHhHo1vLl1ke6kzc/Lbh0AIPIRxAE4IjHB3uqodusiXXubn5fdOgBA5COIA3DEmMzurtZFOrvrgrOeOADELoI4AEeM7N8t5KvbiQnxGtm/m0Mdeatv10QNSU0KqWZoahI7bQJADCOIA3DMlBHpjp4fbabl9VGcCe7cOCNNzevjbEMAAE8RxAE45t6c3hqbeVVQ596V1V335vR2uCNvZacna86Ya5sM43FGmjtmAGMpwJHd0rt/lArmB94f2e11R0BYcRcQAEf9btxA9e2aqEXriutdESUxIV5TRqTHfAivNX5wT3W/8nItzN+nzfWsKz40NUlT8/oQwtGylayXCuZJZYV1j6VkSzkzpLRcl5sCws9YVpDbvEURY8z2zMzMzO3bt3vdCoALvLHrsFYWHZKvqkaJCfEak9k9ZmfCg7G33KfC4gqdrKpR+4R4ZacnMxMOFD0rrZ4mWf6GzzFx0uiFUuZE9/oCGpCVlaWioqIiy7KyQq3lijgA14zs361FB+9L9e2aSPAGLlSyvukQLgWOr54qdezBlXFENYI4HMGVvi/xWgBAkArmNR3Ca1n+wOx4Wq6THQGOIogjrAqLK7Qgf5+21DP7OiQ1SdNa0OwrrwUAhODI7vpnwhtTtjFQ1yXDmZ4AhxHEETYvbj2gWSvfl7+B2w62lFZq4pLNmjtmgMYN7uFucy7jtajf0sJSvbD1oE6fqdHlreM1YXAPTcpO9botAJGgpMB+HUEcUYogjrAoLK5oNHjW8lvSzJU7ddWVbWP2ajCvRV2zVuzU8m0HdfaS12T26g/0yJoPNG5QD80ZO8Cb5gBEhmqfu3VABGAdcYTFgvx9TQbPWn5LWpi/z9mGPMRrcbExTxXq+a11Q3its5b0/NaDuvMP77jbGIDI0sbmvTN264AIEDFB3BjzPWOMde7tB173g+DtLffVOwfdmM2lldpbHntXMXgtLjZrxU4VHTgR1Lnbyo5r1oqdDncEIGKl5bhbB0SAiAjixpgekhZJOul1LwhdYXGFq3WRjNfiYsu3HXT0fAAxpEtGYLOeUKQMZz4cUc3zIG6MMZKekXRM0h89bgc2nKxnt0Qn6yIZr8WXlhaWNjiO0pCzVqAOQAuVMyOwWU8wTJyUM93ZfgCHeR7EJU2VdJOkyZJOedwLbGifYO+eX7t1kYzX4ksvbLV3ddtuHYAYkJYrjV7QdBiv3VkzLdf5ngAHeRrEjTEZkuZKWmBZ1tte9gL77K74EYsrhfBafOn0GXtX+e3WAYgRmd+XJq4KjJ3UJ2V44Djb2yMGeHYZzhgTL2mZpAOSfmbzObY3cKif3b4Qur5dEzUkNSmkmxSHpibF5O6SvBZfury1vW8vdusAxJC03MDbkd2BdcKrfYHVUdJymAlHTPHyivgvJF0naZJlWZ972AfCYFpeH8WZ4M6NM9LUvD7ONuQhXouACTY3KrJbByAGdcmQrv+3wCz49f9GCEfM8SSIG2OGKnAV/HeWZW2y+zyWZWXV9yZpT9iaRVCy05M1Z8y1TQbQOCPNHTMgJkcxavFaBBzxVblaBwBAtHE9iJ8bSXlW0l5JD7r98eGc8YN7atk9QzU0Nane40NTk7TsnqEtYkt3Xgvp5e0fuVoHAEC08WIYs72kvuf+uyqwemEdfzLG/EmBmzjvc60zNFt2erKy05O1t9ynwuIKnayqUfuEeGWnJ8fkHHRjWvprUV1z1tU6AACijRdBvFrSkgaOZSowN75R0v9Jsj22Am/17ZrYIsJmMFrqa9EmvpWk0FdACdQBABD7XA/i527MrHcLe2PMbAWC+P9YlvXfbvYFILzuzLpKT60vsVUHAEBLEAkb+gCIQTNG2VvdwG4dAADRhiAOwDEjvtrZ0fMBAIhmERXELcuabVmWYSwFiA3PTB6idq2Dm/lu17qVnpk8xOGOAACIHBEVxAHElsUFH+rUmeBWQTl15qwWF3zocEcAAEQOgjgAxyxaV+zo+QAARDOCOABHvLHrsHxVoS1f6Kuq0Ru7DjvUEQAAkYUgDsARK4sOuVoHAEC0IYgDcESoV8ObWwcAQLQhiANwRGKCvf3C7NYBABBtCOIAHDEms7urdQAARBuCOABHjOzfLeSr24kJ8RrZv5tDHQEAEFkI4gAcM2VEuqPnAwAQzQjiABxzb05vjc28Kqhz78rqrntzejvcEQAAkYO7ogA46nfjBqpv10QtWldc74ooiQnxmjIinRAOAGhxCOIAHHdvTm/dm9Nbb+w6rJVFh+SrqlFiQrzGZHZnJhwA0GIRxAG4ZmT/bgRvAADOYUYcAAAA8ABBHAAAAPAAQRwAAADwAEEcAAAA8ABBHAAAAPAAq6YAAIDIdGS3VFIgVfukNolSWo7UJcPrroCwIYiH0d5ynwqLK3SyqkbtE+KVnZ6svl0TvW4LAIDoUrJeKpgnlRXWPZaSLeXMkNJyXW4KCD+CeBgUFldoQf4+bSmtrHNsSGqSpuX1UXZ6sgedAQAQZYqelVZPkyx//cfLCqVld0ijF0qZE93tDQgzZsSb6cWtBzRxyeZ6Q7gkbSmt1MQlm7V860GXOwMAIMqUrG88hNey/NLqqYHzgShGEG+GwuIKzVr5vvxW4+f5LWnmyp0qLK5wpzEAAKJRwbymQ3gtyy8VzHe2H8BhBPFmWJC/r8kQXstvSQvz9znbEAAA0erI7vpnwhtTtjFQB0QpgrhNe8t9DY6jNGRzaaX2lvsc6ggAgChWUuBuHRABCOI22R0zYTwFAIB6VNu8UGW3DogABHGbTlbVuFoHAEBMa2NzuV+7dUAEIIjb1D7B3sqPdusAAIhpaTnu1gERgCBuk911wVlPHACAenTJCGzWE4qU4ey0iahGELepb9dEDUlNCqlmaGoSO20CANCQnBmSCTKamDgpZ7qz/QAOI4g3w7S8PoozwZ0bZ6SpeX2cbQgAgGiWliuNXtB0GDdxgZ0103Kd7wlwEEG8GbLTkzVnzLVNhvE4I80dM4CxFAAAmpL5fWniqsDYSX1ShgeOs709YgB3DjbT+ME91f3Ky7Uwf58217Ou+NDUJE3N60MIBwAgWGm5gbcjuwPrhFf7AqujpOUwE46YQhAPg+z0ZGWnJ2tvuU+FxRU6WVWj9gnxyk5PZiYcAAC7umQQvBHTCOJh1LdrIsEbAAAAQWFGHAAAAPAAQRwAAADwAEEcAAAA8ABBHAAAAPAAQRwAAADwAEEcAAAA8ABBHAAAAPAAQRwAAADwABv6AAA8x87EAFoigjgAwDOFxRVakL9PW0or6xwbkpqkaXl9lJ2e7EFnAOA8RlMAAJ54cesBTVyyud4QLklbSis1cclmLd960OXOAMAdBHEAgOsKiys0a+X78luNn+e3pJkrd6qwuMKdxgDARQRxAIDrFuTvazKE1/Jb0sL8fc42BAAeIIgDAFy1t9zX4DhKQzaXVmpvuc+hjgDAGwRxAICr7I6ZMJ4CINYQxAEArjpZVeNqHQBEKoI4AMBV7RPsrZxrtw4AIhVBHADgKrvrgrOeOIBYQxAHALiqb9dEDUlNCqlmaGoSO20CiDkEcQCA66bl9VGcCe7cOCNNzevjbEMA4AGCOADAddnpyZoz5tomw3ickeaOGcBYCoCYxJ0vAABPjB/cU92vvFwL8/dpcz3rig9NTdLUvD6EcAAxiyAOAPBMdnqystOTtbfcp8LiCp2sqlH7hHhlpyczEw4g5hHEAQCe69s1keANoMVhRhwAAADwAEEcAAAA8ABBHAAAAPAAQRwAAADwAEEcAAAA8ABBHAAAAPAAQRwAAADwgCdB3BjTyRjzA2PMKmNMsTHmc2PMp8aYjcaYe4wx/IAAAACAmObVhj53SfqDpE8krZN0QFJXSWMk/bekm40xd1mWZXnUHwAAAOAor4L4XknfkvRXy7L8tQ8aY34maYuksQqE8hXetAcAAJzm9/tVWVkpn8+n6upqcf0NXjPGqE2bNkpMTFRSUpLi4pwd0vBkBMSyrLcsy1p9YQg/9/hhSX8898dc1xsDAACu8Pv9OnjwoI4ePaqqqipCOCKCZVmqqqrS0aNHdfDgQfn9/qaLmsGrK+KN+eLc+xpPuwAAAI6prKzU6dOnFR8fr27duqldu3aOX30EmuL3+3Xq1CkdPnxYp0+fVmVlpZKTkx37eBEVxI0x8ZK+f+6Pa4M4f3sDh/qFrSkAABB2Pp9PktStWzclJiZ63A0QEBcXd/7r8dChQ/L5fI4G8Uj70XOupGskvWpZ1uteNwMAAJxRXV0tSWrXrp3HnQB11X5d1n6dOiVirogbY6ZK+omkPZImBlNjWVZWA8+1XVJm+LoDAADhVDsTzjgKIpExRpIcv3chIr76jTFTJC2Q9IGkEZZlVXrcEgAAAFqo2iDuNM+DuDHmPkm/l/QPBUL4YY9bAgAAABznaRA3xjwg6XFJ7ykQwo942Q8AAADgFs+CuDHmQQVuztwuKc+yrAqvegEALywtLNWoJ97WjfPe0qgn3tbSwlKvWwKAoPz85z+XMUYbN248/1hNTY2MMfrGN74R9PO8+eabMsbo0UcfdaLNiOfJzZrGmH+V9LCks5I2SJpazyzOfsuylrrcGgA4btaKnVq+7aDOXnIP0OzVH+iRNR9o3KAemjN2gDfNAXBVU7PIzzzzjCZNmuROM3CdV6umpJ5730rSfQ2cUyBpqSvdAIBLxjxVqKIDJxo8ftaSnt96UPuOnNTL/36Di50BsWtvuU+FxRU6WVWj9gnxyk5PVt+ukbV2+S9/+ct6Hx84cKDLnQTnvvvu0/e+9z2lpKR43UpU8ySIW5Y1W9JsLz42AHhl1oqdjYbwC20rO65ZK3ZyZRxohsLiCi3I36ctpXUXYxuSmqRpeX2Une7cZi2hmD17ttcthCQ5OdnRjW5aCs9XTQGAlmL5toOOng/gSy9uPaCJSzbXG8IlaUtppSYu2azlW6Pr79mpU6f061//Wl/72tfUrl07tW/fXjfccINefPHFOudWV1fr97//vW6++WalpKSoTZs2SkpK0je/+U29/nr9+ya+9957Gj9+vHr16qU2bdqoc+fOysrK0v3336+zZ8+eP6++GfELHTp0SN/97nfVuXNntW3bVoMGDaq3x8YcO3ZMDzzwgPr166eEhAR17NhR3/zmN/Xmm2+G9DyRLGI29AGAWLa0sLTOTHhTzlqBuknZqU2fDOC8wuIKzVr5vvxN/J3zW9LMlTt11ZVtI+bKeGOOHz+uESNGaMeOHcrKytLdd98tv9+vtWvXasKECdq9e/dFV9aPHj2q++67TzfccIO++c1vqnPnzvrkk0/0l7/8RTfffLOefvrpi+bP//73v2vYsGFq1aqVvvWtb6lXr1767LPPtG/fPj355JOaM2eOWrVq1WSfx44d0w033KDk5GTdfffdOn78uJYvX64JEybo448/1v3339/kc5SWlmrEiBEqKyvTjTfeqFtuuUU+n09r1qzRyJEjtWTJEk2ePNnOyxhRCOIA4IIXbF51e2HrQYI4EKIF+fuaDOG1/Ja0MH+f50G8vtGUXr16XRSU/+u//ks7duzQ7373O/34xz8+//jnn3+ub33rW3r44Yc1duxYXXvttZIC4yMHDhzQVVddddHznjhxQsOGDdP06dP17W9/W23atJEkLV26VNXV1VqzZo1uvfXWi2oqKyvPn9eU9957T9/+9rf13HPPnb8Z9YEHHlBWVpZmzpypMWPGNDlbPnHiRB04cEDLly/XXXfddf7x48eP68Ybb9SUKVN02223qXPnzkH1FKkYTQEAF5w+U+NqHdBS7S33NTiO0pDNpZXaW+5zqKPgPPTQQ3Xeli5dev74kSNH9Pzzz+v666+/KIRLUtu2bTV37lxZlqXnn3/+/OMJCQl1QrgkdezYUZMnT1ZFRYW2b99e53jbtm3rPJaUlBT0bpPx8fGaO3fuRef37t1bU6ZM0ZkzZ/TnP/+50frt27ersLBQ48ePvyiES9KVV16p2bNn6/Tp01q1alVQ/UQyrogDgAsub23v263dOqClKiy2ty1JYXGFpyupWFbjl/C3bNkiv98vy7LqvXpeXV0tSdq9e/dFj7///vuaP3++Nm7cqI8//vj8ebU++uij8/89YcIELVq0SKNHj9add96pb3zjG7rhhhvUu3fvkD6X1NRU9ezZs87jubm5+tWvfqW///3vjdZv2rRJUuDqd32fa3l5uaS6n2s04js8ALhgwuAemr36A1t1AIJ3ssreb5Hs1rnl2LFjkqTNmzdr8+bNDZ538uTJ8/9dWFiob3zjG/L7/crLy9Ptt9+uxMRExcXFqaioSKtXr74omA8bNkxvv/22fv3rX2v58uV69tlnJUn9+vXT7NmzNX78+KB67dq1a72Pd+vWTZL06aefBvW5vv766w3eVHrp5xqtCOIA4IJJ2al6ZM0HId2w2cqI+XAgRO0T7EUbu3Vu6dChgyRp+vTpmjdvXlA1jzzyiKqqqrRhwwYNHz68zrHVq1fXqcnOztZf//pXVVdXa9u2bXrttde0aNEiffvb31bXrl2Vm5vb5MetvWJ9qcOHD1/0uTSk9viTTz6p//iP/2jy40UzZsQBuGZvuU/PFJbq9/n79ExhqeczmW4bNyi0q9uhng9Atm+69PpmzaYMHTpUxhht2LAh6Jri4mJ16dKlTgiXpIKCgkZr27Rpo+zsbD366KN6/PHHZVmWXnnllaA+bmlpqQ4erHuD+vr16yVJ1113XaP1119/vSSF9LlGK4I4AMcVFldo3OJNGvn423po9Qf63d/26qHVH2jk429r3OJNtmc6o82csQOU2bNjUOcOSrmSzXwAG/p2TdSQ1KSQaoamJkXcTpuX+spXvqIJEybo3Xff1Zw5cy5a07tWcXGxysrKzv+5V69eOnr0qHbt2nXReYsXL1Z+fn6d+nfeeUdVVVV1Hq+9wn355ZcH1WtNTY0eeOCBi+beP/zwQy1atEiXXXaZvvvd7zZaf/3112vYsGFavny5/ud//qfec3bs2KGKiuj/tyOyfw8DIOq9uPVAo+v51m6qMXfMAI1rAfPQK/8jW7NW7NTybQfrHVNpZQJXwgnhgH3T8vpo4pLNQS1hGGekqXl9nG8qDP7whz+ouLhYP/vZz7R06VINHz78/NrgH3zwgbZt26aXXnrp/NKA999/v/Lz83XDDTdo3LhxuuKKK7RlyxZt2rRJY8eO1YoVKy56/l//+tfasGGDvv71rys1NVXt2rXTP/7xD7322mtKSkrSD3/4w6D6HDhwoDZu3KisrCyNHDlSlZWVWr58uT799FM99thj6tWrV5PP8cILLygvL0+TJk3SE088oSFDhqhjx446dOiQ3nvvPX3wwQfaunVr1O/uSRAH4JhY3VSjueaMHaA5YwdoaWGpXth6UKfP1Ojy1vGaMLgHM+FAGGSnJ2vOmGub/P4TZ6S5YwZEzfedDh06aMOGDVq8eLGef/55vfzyy6qurlbXrl3Vp08fPfHEE7rpppvOn3/rrbfqlVde0a9+9Su98MILio+P15AhQ7R+/Xrt2bOnThCfMmWKkpOTtXnzZm3YsEFnz55V9+7dNWXKFP3kJz+pdyWU+nTq1EmrV6/WAw88oCVLlsjn86l///6aPn26JkyYENRz9OzZU9u3b9fChQu1cuVKPffcc/L7/erWrZuuvvpq3Xfffbr66quDf/EilGlquZxoZIzZnpmZmVnf2pgA3DNu8aaQ1vMdmpqkF+8d5mBHACJF7dJzGRkZjn2MwuIKLczfp831fB8ampqkqXl9oiaEw33Bfo1mZWWpqKioyLKsrFA/BlfEATiiOZtqRPqsJoDokJ2erOz0ZO0t96mwuEInq2rUPiFe2enJfJ9BRCCIA3BEtG6qASD29O2ayPcVRCRWTQHgiFjdVAMAgHAhiANwRKxuqgEAQLjwLx4AR8TqphqA05hnBloOgjgAR9RuqhHqqikEDrRUhcUVWpC/r96/M0NSkzSNFT6AmMNoCgDHTMvrozgT3LnRtKkGEG4vbj2giUs2N/iDa+3GV8u31t02HED0IogDcEztphpNhfFo21QDCKdQN76yuyIRgMhDEAfgqPGDe2rZPUM1NDWp3uNDU5O07J6hLWJ7e6A+C/L3BbUVuxQI4wvz9znbEADXMCMOwHFsqgHUj42vgJaNIA7ANWyqAVyMja+Alo3RFAAAPMLGV0DLRhAHAMAjbHwFtGwEcQDwyBu7Duvflm3Td//0rv5t2Ta9seuw1y3BZWx8hXD67LPPNHXqVPXq1Uvx8fEyxui9997zuq2L7N+/X8YYTZo06aLHJ02aJGOM9u/fH/Rz9erVS7169Qprf27jR2oAcNnigg+1aF2xfJeMF6zdVa7EhHhNGZGue3N6e9Qd3MTGVzAmsL6rZQW5dE4jZsyYocWLF+u2227TxIkT1apVK3Xr1q3ZzwvnEMQBwEU/Wf6eVhR91OBxX1WN5ry2R8VHTmr+XV9zsTN4ZVpeH01csjmoJQzZ+MqmI7ulkgKp2ie1SZTScqQuGV53FXZr1qxR3759tXr1aq9badBVV12l3bt3q0OHDl63EhEI4gDgksUFHzYawi/00vZDSu/SnivjLUDtxldNberDxlc2lKyXCuZJZYV1j6VkSzkzpLRcl5tyzscff6wbb7zR6zYaddlll6lfv35etxExmBEHAJcsWlfs6PmIXmx85YCiZ6Vld9QfwqXA48vukIqWudtXEC6co96/f78mTJig5ORkJSQkaNCgQVqzZs1F5+fm5soYI8uyVFBQIGOMjDHKzc296LzXX39dt9xyi5KTk9WmTRv17t1b06dP14kTJ+r0sG7dOv3oRz/S1VdfrSuuuEJt27bVNddco4ceekhVVVV1zvf5fHrkkUd0zTXX6IorrlBiYqJ69+6t8ePHa/v27fV+bvXx+/167LHH1K9fPyUkJKh79+66//779dlnn4X0Gj7//PMaMWKEOnbsqISEBGVkZOjRRx9VdXV1SM/jNK6IAw57Y9dhrSw6JF9VjRIT4jUms7tG9mdmr6V5Y9fhOjPhTfFV1eiNXYf5emkh2PgqjErWS6unSZa/8fMsv7R6qtSxR0ReGS8rK9OQIUOUlpamiRMnqrKyUi+++KJuv/12vfnmmxoxYoSkwI2Oubm5euihh5SSknI+5F54I+NDDz2k2bNnKykpSbfddpu6dOminTt36re//a1effVVbdq0SVdcccX583/zm99oz549uuGGG3TrrbeqqqpKhYWFmj17ttavX68333xTrVq1khSYbx81apTeeecdDRs2TD/4wQ8UHx+vQ4cOad26dfr617+urKysoD7n+++/X2+//bbGjRun22+/Xa+//rqeeOIJbdiwQRs3blRCQkKTz3H33XfrmWeeUffu3TV27Fh17NhR7777rh588EHl5+frb3/7m+LjIyMCR0YXQAzihjxcaGXRIdt1BPGWhY2vwqBgXtMhvJbllwrmR2QQX79+vWbPnq1f/vKX5x/7zne+o1GjRmn+/PkXBXEpELZ79eql2bNnX/Q869at0+zZszVs2DC9+uqr6tix4/ljS5cu1eTJk/XLX/5Sjz/++PnHn3rqKaWmpp6/mbTWgw8+qEcffVQvv/yyxo8fL0n6xz/+oXfeeUf/8i//olWrVl10vt/v16effhr051xYWKj33ntPKSkpkqQ5c+borrvu0sqVKzV//nw9+OCDjdYvXbpUzzzzjO644w4999xzatu27fljs2fP1kMPPaQnn3xS06ZNC7onJzGaAjjgJ8vf05zX9jR4BbT2hrzpL+1wuTN4JdSr4c2tA1qsI7sbHkdpSNnGQF2ESUlJ0c9//vOLHvvnf/5n9ezZU1u2bAn6eRYuXChJ+tOf/nRRCJcCIX7gwIF67rnnLno8LS2tTgiXAlespcCYy6UuDL214uLidOWVVwbd67Rp086H8Nr6+fPnKy4uTk8//XST9QsWLFB8fLyefvrpOv08+OCD6tSpU53P1UtcEQfCjBvyUJ9Emxuw2K0DWqySAvt1EbaSysCBA8+Pf1yoR48e2rRpU9DPs2nTJl122WV66aWX9NJLL9U5fubMGR09elTHjh1Tp06dJEmnTp3SggULtGrVKu3du1c+n++iJRY/+ujLf+euvvpqDRw4UM8//7zKysp0++23a/jw4Ro0aJBat24dyqesnJycOo+lpaWpR48e2r9/v06cOFHnh4lap0+f1o4dO5ScnKwnnnii3nPatGmj3bsj54cuvsMDYWbnhjyCeOwbk9lda3eV26oDEIJqn7t1DmoocMbHx8vvD3L0RtKxY8dUU1Ojhx56qNHzTp48qU6dOumLL77QTTfdpC1btuiaa67R+PHj1blzZ1122WWSAiMwF9702KpVK7311lt6+OGH9fLLL+uBBx6QJCUmJupf//VfNWfOHLVv3z6oXrt27Vrv4926dVNZWZk+/fTTBl+X48ePy7IsHT16tMnPNVIQxIEw4oY8NGRk/25KTIgP6esjMSGerwsgVG1sztfbrYsCHTp0kN/vV2VlcBtHvfLKK9qyZYsmTZqkZ5555qJjn3zySb0h98orr9Tjjz+uxx9/XMXFxSooX31amAAAFoNJREFUKNDixYu1aNEinThxQsuWBbc6TXl5ub761a/Wefzw4cPnP5eG1B677rrrVFRUFNTH8xoz4kAYNeeGPMS+KSPSHT0fgAKb9bhZFwWuv/56HT9+XLt27Qrq/OLiwG92x4wZU+dYQUHToz/p6em65557VFBQoPbt2+uVV14Jutf6nr+kpEQHDx5Ur169GrwaLknt27dX//79tWvXrqB/6PAaQRwII27IQ2PuzemtsZlXBXXuXVndGVkC7OiSEdisJxQpwyNuPjycam+w/OEPf6iPP/64zvFTp07p3XffPf/n2mUP169ff9F5JSUl58dOLlRaWqqSkpI6jx8/flzV1dX13sTZkAULFqisrOz8n/1+v6ZPny6/36/Jkyc3Wf/jH/9YZ86c0d13313v+ujHjx+PqKvljKYAYcQNeWjK78YNVN+uifUubSmJpS2BcMiZEdisJ5glDE2clDPd+Z48lJeXp7lz52rWrFnq06ePbrnlFqWmpurkyZMqKytTQUGBhg8frrVr10qSRo8erfT0dD322GN6//33dd111+nAgQNas2aNbr31Vh04cOCi59+xY4fGjBmjwYMHKyMjQ//0T/+ko0eP6pVXXtEXX3xRb3hvSHZ2tgYOHKjx48erQ4cOev3117Vjxw5lZWVpxowZTdbffffd2r59u5566in17t37/CozlZWVKi0t1dtvv63Jkyfrj3/8Y2gvokP41x8II27IQzDu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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "image/png": {
       "height": 248,
       "width": 369
      },
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from pymoo.util import plotting\n",
    "\n",
    "_X = np.row_stack([a.pop.get(\"X\") for a in res.history])\n",
    "feasible = np.row_stack([a.pop.get(\"feasible\") for a in res.history])[:, 0]\n",
    "\n",
    "plotting.plot(_X[feasible], _X[np.logical_not(feasible)], res.X[None,:]\n",
    "              , labels=[\"Feasible\", \"Infeasible\", \"Best\"])"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
